﻿using AutoMapper;
using HelenServer.Migrator;
using HelenServer.UserCenter.Contracts;
using Microsoft.EntityFrameworkCore;

namespace HelenServer.UserCenter.Dal;

public class UserCenterMigrateProfile : Profile
{
    protected internal static ZentaoDbContext ZtContext => MigrateProvider.Context ?? throw new InvalidOperationException("请先调用MigrateProvider.ReadyToMigrate方法");

    protected internal static UserCenterDbContext UcContext
        => new Lazy<UserCenterDbContext>(() =>
        {
            var config = Helen.Services.GetRequiredService<IConfiguration>();
            var connectionString = config.GetConnectionString("master");

            return new UserCenterDbContext(new DbContextOptionsBuilder<UserCenterDbContext>().UseSqlServer(connectionString).Options);
        }).Value;

    public UserCenterMigrateProfile()
    {
        this.CreateMap<ZtDept, Department>()
            .ForMember(dest => dest.Parent, member => member.MapFrom(source => MapVirtualDepartment((int)source.Parent)))
            .ForMember(dest => dest.Manager, member => member.MapFrom(source => MapVirtualUser(source.Manager)));

        this.CreateMap<ZtGroup, Position>()
            .ForMember(dest => dest.Role, member => member.MapFrom(source => MapVirtualRole(source.Role)))
            .ForMember(dest => dest.Description, member => member.MapFrom(source => source.Desc));

        this.CreateMap<ZtUser, User>()
            .ForMember(dest => dest.Username, member => member.MapFrom(source => source.Account))
            .ForMember(dest => dest.Password, member => member.MapFrom(source => Helen.Encrypt("**")))
            .ForMember(dest => dest.Department, member => member.MapFrom(source => MapVirtualDepartment((int)source.Dept)))
            .ForMember(dest => dest.Position, member => member.MapFrom(source => MapVirtualPosition(source.Role)))
            .ForMember(dest => dest.Name, member => member.MapFrom(source => source.Realname))
            .ForMember(dest => dest.Sex, member => member.MapFrom(source => source.Gender == "m" ? 1 : 0))            
            .ForMember(dest => dest.InductionDate, member => member.MapFrom(source => MapInductionDate(source.Join)))
            .ForMember(dest => dest.ClientStatus, member => member.MapFrom(source => Helen.ToEnum<ClientStatus>(source.ClientStatus)))
            .ForMember(dest => dest.Deleted, member => member.MapFrom(source => source.Deleted == "1"));
    }

    private static Department? MapVirtualDepartment(int value)
    {
        return value is 0 ? null : new Department { Id = value };
    }

    private static Role? MapVirtualRole(string value)
    {
        if (_roles is null || _roles.Count == 0)
        {
            _roles = UcContext.Roles.ToList();
        }

        if (string.IsNullOrEmpty(value))
        {
            return null;
        }

        var langEntity = MigrateProvider.DbCache.ZtLangs.FirstOrDefault(n => n.Section == "roleList" && n.Key == value);

        return langEntity is null ? _roles.First() : _roles.First(n => n.Name == langEntity.Value);
    }

    private static User? MapVirtualUser(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return null;
        }

        var entity = MigrateProvider.DbCache.ZtUsers.First(n => n.Account == value);

        return entity is not null ? new User { Id = (int)entity.Id } : null;
    }

    private static Position? MapVirtualPosition(string value)
    {
        if (_positions is null || _positions.Count == 0)
        {
            _positions = UcContext.Positions.ToList();
        }

        if (string.IsNullOrEmpty(value))
        {
            return null;
        }

        var roleName = MigrateProvider.DbCache.ZtLangs.First(n => n.Section == "roleList" && n.Key == value).Value;

        var entity = _positions.First(n => n.Role is not null && n.Role.Name == roleName);

        return entity is null ? null : entity;
    }

    private static DateTime? MapInductionDate(DateOnly date)
    {
        return DateTime.TryParse(date.ToString(), out var time)
            ? time > Helen.MinimumDate ? time : null : null;
    }

    private static List<Role> _roles = null!;
    private static List<Position> _positions = null!;

    public static async ValueTask DisposeAsync()
    {
        await UcContext.DisposeAsync();

        _roles.Clear();
        _roles = null!;

        _positions.Clear();
        _positions = null!;
    }
}